home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
kernel
/
tty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
29KB
|
813 lines
/* This file contains the terminal driver, both for the IBM console and regular
* ASCII terminals. It is split into two sections, a device-independent part
* and a device-dependent part. The device-independent part accepts
* characters to be printed from programs and queues them in a standard way
* for device-dependent output. It also accepts input and queues it for
* programs. This file contains 2 main entry points: tty_task() and keyboard().
* When a key is struck on a terminal, an interrupt to an assembly language
* routine is generated. This routine saves the machine state and registers
* and calls keyboard(), which enters the character in an internal table, and
* then sends a message to the terminal task. The main program of the terminal
* task is tty_task(). It accepts not only messages about typed input, but
* also requests to read and write from terminals, etc.
*
* The device-dependent part interfaces with the IBM console and ASCII
* terminals. The IBM keyboard is unusual in that keystrokes yield key numbers
* rather than ASCII codes, and furthermore, an interrupt is generated when a
* key is depressed and again when it is released. The IBM display is memory
* mapped, so outputting characters such as line feed, backspace and bell are
* tricky.
*
* The valid messages and their parameters are:
*
* HARD_INT: a character has been typed (character arrived interrupt)
* TTY_READ: a process wants to read from a terminal
* TTY_WRITE: a process wants to write on a terminal
* TTY_IOCTL: a process wants to change a terminal's parameters
* TTY_SETPGRP: indicate a change in a control terminal
* CANCEL: terminate a previous incomplete system call immediately
*
* m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS
* |-------------+---------+---------+---------+---------+---------+---------|
* | HARD_INT |minor dev| | | | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | TTY_READ |minor dev| proc nr | count | | | buf ptr |
* |-------------+---------+---------+---------+---------+---------+---------|
* | TTY_WRITE |minor dev| proc nr | count | | | buf ptr |
* |-------------+---------+---------+---------+---------+---------+---------|
* | TTY_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | TTY_SETPGRP |minor dev| proc nr | | | | |
* |-------------+---------+---------+---------+---------+---------+---------
* | CANCEL |minor dev| proc nr | | | | |
* ---------------------------------------------------------------------------
*/
#include "kernel.h"
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include <sgtty.h>
#include "proc.h"
#include "tty.h"
#if (CHIP == INTEL)
#include "ttymaps.h"
#endif
PUBLIC void finish();
PUBLIC void tty_reply();
PUBLIC void sigchar();
PRIVATE void do_int();
PRIVATE void charint();
PRIVATE void in_char();
PRIVATE void echo();
PRIVATE void do_read();
PRIVATE void do_write();
PRIVATE void do_ioctl();
PRIVATE void do_setpgrp();
PRIVATE void do_cancel();
/*===========================================================================*
* tty_task *
*===========================================================================*/
PUBLIC void tty_task()
{
/* Main routine of the terminal task. */
message tty_mess; /* buffer for all incoming messages */
register struct tty_struct *tp;
output_done = 0;
tty_init(); /* initialize */
init_rs232();
while (TRUE) {
receive(ANY, &tty_mess);
tp = &tty_struct[tty_mess.TTY_LINE];
switch(tty_mess.m_type) {
case HARD_INT: do_int(); break;
case TTY_READ: do_read(tp, &tty_mess); break;
case TTY_WRITE: do_write(tp, &tty_mess); break;
case TTY_IOCTL: do_ioctl(tp, &tty_mess); break;
case TTY_SETPGRP: do_setpgrp(tp, &tty_mess); break;
case CANCEL: do_cancel(tp, &tty_mess); break;
default: tty_reply(TASK_REPLY, tty_mess.m_source,
tty_mess.PROC_NR, EINVAL, 0L, 0L);
}
}
}
/*===========================================================================*
* do_int *
*===========================================================================*/
PRIVATE void do_int()
{
/* The TTY task can generate two kinds of interrupts:
* - a character has been typed on the console or an RS232 line
* - an RS232 line has completed a write request (on behalf of a user)
* If either interrupt happens and the TTY task is idle, the task gets the
* interrupt message immediately and processes it. However, if the TTY
* task is busy, a bit is set in 'busy_map' and the message pointer stored.
* If multiple messages happen, the bit is only set once. No input data is
* lost even if this happens because all the input messages say is that there
* is some input. The actual input is in the tty_driver_buf array, so losing
* a message just means that when the one interrupt-generated message is given
* to the TTY task, it will find multiple characters in tty_driver_buf.
*
* The introduction of RS232 lines has complicated this situation somewhat. Now
* a message can mean that some RS232 line has finished transmitting all the
* output given to it. If a character is typed at the instant an RS232 line
* finishes, one of the two messages may be overwritten because MINIX only
* provides single buffering for interrupt messages (in proc.c).To avoid losing
* information, whenever an RS232 line finishes, the flag tty_waiting is set
* to COMPLETED and kept that way until its completion is processed and a
* message sent to FS saying that output is done. The number of RS232 lines in
* COMPLETED state is kept in output_done, which is checked on each interrupt,
* so that a lost HARD_INT line completion interrupt will be quickly
* recovered.
*
* In short, when this procedure is called, it can check for RS232 line done
* by inspecting output_done and it can check for characters in the input
* buffer by inspecting tty_driver_buf[0]. Thus losing a message to the TTY
* task is not serious because the underlying conditions are explicitly checked
* for on each interrupt.
*/
/* First check to see if any RS232 lines have completed. */
if (output_done > 0) {
/* If a message is sent to FS for RS232 done, don't process any input
* characters now for fear of sending a second message to FS, which
* would be lost.
*/
if (tty_o_done()) {
return;
}
}
charint(); /* check for input characters */
}
/*===========================================================================*
* charint *
*===========================================================================*/
PRIVATE void charint()
{
/* A character has been typed. If a character is typed and the tty task is
* not able to service it immediately, the character is accumulated within
* the tty driver. Thus multiple chars may be accumulated. A single message
* to the tty task may have to process several characters.
*/
int m, n, count, replyee, caller, old_state;
char *ptr, *copy_ptr, ch;
struct tty_struct *tp;
old_state = lock();
ptr = tty_driver_buf; /* pointer to accumulated char array */
copy_ptr = tty_copy_buf; /* ptr to shadow array where chars copied */
n = tty_buf_count(ptr); /* how many chars have been accumulated */
count = n; /* save the character count */
n = n + n; /* each char occupies 2 bytes */
ptr += 4; /* skip count field at start of array */
while (n-- > 0)
*copy_ptr++ = *ptr++; /* copy the array to safety */
ptr = tty_driver_buf;
tty_buf_count(ptr) = 0; /* accumulation count set to 0 */
restore(old_state);
/* Loop on the accumulated characters, processing each in turn. */
if (count == 0) return; /* on HARD_INT interrupt, count might be 0 */
copy_ptr = tty_copy_buf;
while (count-- > 0) {
ch = *copy_ptr++; /* get the character typed */
n = *copy_ptr++; /* get the line numb